/*
    Copyright (C) 2005-2008  Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*/
/**
 * \file uffs_os_linux.c
 * \brief emulation on linux host
 * \author Ricky Zheng
 */
#include <ddk.h>
#include <mutex.h>
#include <event.h>

#include "uffs/uffs_os.h"
#include "uffs/uffs_public.h"
#include <stdio.h>
#include <stdlib.h>

#define PFX "linuxemu:"

IMutex * g_pIMux = NULL;
#define printf kprintf

extern void * FsKmalloc(UInt32 n);
extern void FsKfree(void *add);

int uffs_InitCS()
{
    g_pIMux = new CMutex();
    if (g_pIMux == NULL) {
        printf("uffs_InitCS failed\n");
        return E_OUT_OF_MEMORY;
    }

    g_pIMux->AddRef();
    return NOERROR;
}

void uffs_UninitCS()
{
    if (g_pIMux) {
        g_pIMux->Release();
        g_pIMux = NULL;
    }
}

int uffs_MutexCreate()
{
    IMutex *pMutex = new CMutex();
    if (pMutex == NULL) {
        kprintf("pMutex = null");
        return E_OUT_OF_MEMORY;
    }

    return (int)pMutex;
}

int uffs_MutexLock(int mux)
{
    assert(mux != 0);

    WaitResult wr;
    IMutex *pMutex = (IMutex*)mux;

    ECode ec = pMutex->Lock(&wr);
    if (FAILED(ec)) {
        printf("lock FAILED.ec=%08x\n", ec);
        return ec;
    }

    return 0;
}

int uffs_MutexUnlock(int mux)
{
    assert(mux != 0);

    IMutex *pMutex = (IMutex*)mux;

    ECode ec = pMutex->Unlock();
    if (FAILED(ec)) {
        printf("Unlock FAILED.ec=%08x\n", ec);
        return ec;
    }

    return 0;
}

int uffs_MutexDestroy(int mux)
{
    assert(mux != 0);

    IMutex *pMutex = (IMutex*)mux;

    pMutex->Release();

    return 0;
}

int uffs_SemCreate(int n)
{
    return uffs_MutexCreate();
}

int uffs_SemWait(int sem)
{
    return uffs_MutexLock(sem);
}

int uffs_SemSignal(int sem)
{
    return uffs_MutexUnlock(sem);
}

void uffs_SemDestroy(int sem)
{
    uffs_MutexDestroy(sem);
}

/* event functions */
int uffs_EventCreate(int manual, int initState)
{
    IEvent *pIEvent;
    pIEvent = new CEvent(!!manual, initState);
    if (pIEvent == NULL) {
        kprintf("uffs_EventCreate:E_OUT_OF_MEMORY\n");
        return E_OUT_OF_MEMORY;
    }

    assert(pIEvent);

    return (int)pIEvent;
}

int uffs_EventAddRef(int n)
{
    IEvent *pEvent = (IEvent*)n;
    pEvent->AddRef();
    return 0;
}

int uffs_EventWait(int n, int waitTime)
{
    IEvent *pEvent = (IEvent*)n;

    ECode ec;
    WaitResult wr;
    EventState es;

    if (waitTime >= 0) {
        ec = pEvent->TryWait(waitTime, &wr, &es);
    } else {
        ec = pEvent->Wait(&wr, &es);
    }

    if (FAILED(ec)) {
        return -1;
    }

    return 0;
}

int uffs_EventNotify(int n)
{
    IEvent *pEvent = (IEvent*)n;

    return pEvent->Notify(1);
}

int uffs_EventDestroy(int n)
{
    return ((IEvent*)n)->Release();
}

int uffs_OSGetTaskId(void)
{
//    IThread *pCurThread = NULL;
//    ThreadId nThreadID = 0;
//
//    ECode ec = CThread::GetCurrent(&pCurThread);
//    if (FAILED(ec)) {
//        printf("GetCurrent thread FAILED.ec = %08x\n", ec);
//        return 0;
//    }
//
//    ec = pCurThread->GetId(&nThreadID);
//    if (FAILED(ec)) {
//        printf("Get thread id FAILED.ec = %08x\n", ec);
//        nThreadID = 0;
//    }
//
//    pCurThread->Release();
//	return nThreadID;
    return 0;
}

void uffs_CriticalEnter(void)
{
    WaitResult wr;
    g_pIMux->Lock(&wr);
}

void uffs_CriticalExit(void)
{
    g_pIMux->Unlock();
}

unsigned int uffs_GetCurDateTime(void)
{
    SystemTime tvo;

	DzGetSystemTime(&tvo);

//    kprintf("uffs_GetCurDateTime.s=%d\n", tvo.seconds);
//	kprintf("uffs_GetCurDateTime.ms=%u\n", tvo.microseconds);
//    kprintf("GetCur(unsigned int)(tvo.seconds*1000+tvo.microseconds)

	return (unsigned int)(tvo.seconds);//*1000+tvo.microseconds);
}

void * uffs_MemAlloc(uffs_Device *dev, int size)
{
	void *p;
	if (dev && dev->mem) {
	    assert(0);
		//useing native memory allocator
		p = dev->mem->malloc(dev->mem, size);
	}
	else {
		p = FsKmalloc(size);
	}
//	uffs_Perror(UFFS_ERR_NOISY, PFX"alloc 0x%08x: %d bytes\n", p, size);
	return p;
}

void uffs_MemFree(uffs_Device *dev, void *p)
{
//	uffs_Perror(UFFS_ERR_NOISY, PFX"free 0x%08x\n", p);
	if (dev && dev->mem) {
		dev->mem->free(dev->mem, p);
	}
	else {
		FsKfree(p);
	}
}
